package com.flute.tools.word;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import com.flute.tools.util.StringUtil;

public class WordSpliter {

	private HashSet<String> wordSet;
	private static HashMap<String[], WordSpliter> map = new HashMap<String[], WordSpliter>();

	private WordSpliter(String[] words) {
		this.wordSet = new HashSet<String>();
		for (String word : words) {
			this.wordSet.add(word);
		}
	}

	public synchronized static WordSpliter getInstance(String[] words) {
		if (!map.containsKey(words)) {
			map.put(words, new WordSpliter(words));
		}

		return map.get(words);
	}

	public String[] splitWithoutPriority(String string) {
		return split(string, new SameWordsScorer());
	}

	public String[] split(String string, IWordsScorer scorer) {
		String[] words = CommonSpliter.getSeparatedString(string);
		List<String> result = new ArrayList<String>();
		for (String word : words) {
			for (int i = 0;; i++) {
				if (i * 30 > word.length()) {
					break;
				} else {
					List<List<String>> llist = getAllPosibility(word.substring(
							i * 30, Math.min(30 * (i + 1), word.length())));
					result.addAll(getResult(llist, scorer));
				}
			}
		}

		return result.toArray(new String[] {});
	}

	private List<String> getResult(List<List<String>> llist, IWordsScorer scorer) {
		List<String> result = new ArrayList<String>();

		if (llist.size() == 1) {
			result = llist.get(0);
		} else {
			double max = -1;
			for (List<String> list : llist) {
				double score = scorer.score(list);
				if (score > max) {
					max = score;
					result = list;
				}
			}
		}

		return result;
	}

	public List<List<String>> getAllPosibility(String string) {
		// matched words positions
		HashSet<String> words = getMatchWords(string);
		List<WordPosition> posList = new ArrayList<WordPosition>();
		for (String key : words) {
			int[] ids = StringUtil.getAllIndex(string, key);
			for (int i = 0; i < ids.length; i++) {
				WordPosition pos = new WordPosition(ids[i] + 1, ids[i]
						+ key.length());
				pos.setWord(key);
				pos.setSource(new InformationSource(string));
				posList.add(pos);
			}
		}

		Collections.sort(posList, new WordPositionComparator());

		List<List<WordPosition>> slist = getAllPosibility(posList);

		List<List<String>> results = new ArrayList<List<String>>();
		for (List<WordPosition> list : slist) {
			List<String> result = splitWord(list, string, words);
			results.add(result);
		}

		return results;
	}

	private List<String> splitWord(List<WordPosition> list, String string,
			HashSet<String> set) {
		List<String> result = new ArrayList<String>();
		int last = 0;
		for (int i = 0; i < list.size(); i++) {
			WordPosition wp = list.get(i);
			if (wp.getStart() - 1 > last) {
				result.addAll(getString(string.substring(last,
						wp.getStart() - 1), set));
			}
			String value = string.substring(list.get(i).getStart() - 1, list
					.get(i).getEnd());
			if (!StringUtil.isNullOrEmpty(value)) {
				result.addAll(getString(value, set));
			}
			last = wp.getEnd();
		}

		if (last < string.length()) {
			result.addAll(getString(string.substring(last), set));
		}

		return result;
	}

	private List<String> getString(String s, HashSet<String> set) {
		List<String> result = new ArrayList<String>();
		if (!set.contains(s)) {
			String[] words = CommonSpliter.getChineseEnglishSeparatedString(s);
			for (String word : words) {
				if (StringUtil.isAllChineseCharacter(word)) {
					for (char c : word.toCharArray()) {
						result.add(String.valueOf(c));
					}
				} else {
					result.add(word);
				}
			}
		} else {
			result.add(s);
		}

		return result;
	}

	private List<List<WordPosition>> getAllPosibility(List<WordPosition> posList) {
		List<List<WordPosition>> llist = new ArrayList<List<WordPosition>>();
		for (WordPosition pos : posList) {
			boolean added = false;

			for (int i = 0; i < llist.size(); i++) {
				List<WordPosition> list = llist.get(i);
				if (list.size() > 0) {
					if (!pos.isInclusive(list.get(list.size() - 1))) {
						List<WordPosition> newlist = new ArrayList<WordPosition>();
						for (WordPosition pp : list) {
							newlist.add(pp);
						}
						newlist.add(pos);
						llist.add(newlist);
						added = true;
					}
				}
			}
			if (!added) {
				List<WordPosition> newlist = new ArrayList<WordPosition>();
				newlist.add(pos);
				llist.add(newlist);
			}
		}

		// 去掉相互包含的
		for (int i = llist.size() - 1; i > 0; i--) {
			for (int j = i - 1; j >= 0; j--) {
				if (isContains(llist.get(j), llist.get(i))) {
					llist.remove(j);
					i--;
				}
			}
		}

		return llist;
	}

	private boolean isContains(List<WordPosition> shortList,
			List<WordPosition> longList) {
		HashSet<Integer> ssset = new HashSet<Integer>();
		HashSet<Integer> seset = new HashSet<Integer>();
		HashSet<String> svalueSet = new HashSet<String>();
		for (WordPosition wp : shortList) {
			ssset.add(wp.getStart());
			seset.add(wp.getEnd());
			svalueSet.add(wp.getWord());
		}

		HashSet<Integer> lsset = new HashSet<Integer>();
		HashSet<Integer> leset = new HashSet<Integer>();
		HashSet<String> lvalueSet = new HashSet<String>();
		for (WordPosition wp : longList) {
			lsset.add(wp.getStart());
			leset.add(wp.getEnd());
			lvalueSet.add(wp.getWord());
		}

		return lsset.containsAll(ssset) && leset.containsAll(seset)
				&& lvalueSet.containsAll(svalueSet);
	}

	private HashSet<String> getMatchWords(String sentence) {
		HashSet<String> table = new HashSet<String>();
		for (int i = 1; i < 5; i++) {
			String[] words = Spliter.split(sentence, i);
			for (int j = 0; j < words.length; j++) {
				if (wordSet.contains(words[j])) {
					if (words[j].length() > 1) {
						table.add(words[j]);
					}
				}
			}
		}

		return table;
	}
}
